package com.zomiot.portal.aichat.service;

import com.github.houbb.sensitive.word.api.IWordAllow;
import com.github.houbb.sensitive.word.api.IWordDeny;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.github.houbb.sensitive.word.support.allow.WordAllows;
import com.github.houbb.sensitive.word.support.deny.WordDenys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.StreamingChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Service
@Slf4j

public class AiService {

    private final StreamingChatClient chatClient;

    @Value("classpath:prompt/system.md")
    private Resource systemPromptResource;

    @Value("classpath:prompt/knowledge.md")
    private Resource knowledgeResource;

    @Value("classpath:word/deny.txt")
    private Resource wordDenyResource;

    @Value("classpath:word/allow.txt")
    private Resource wordAllowResource;

    private volatile String systemPrompt = "";
    private volatile String knowledgeBase = "";

    private volatile SensitiveWordBs sensitiveWordBs;

    public AiService(StreamingChatClient chatClient,
                     @Value("classpath:prompt/system.md") Resource systemPromptResource,
                     @Value("classpath:prompt/knowledge.md") Resource knowledgeResource,
                     @Value("classpath:word/deny.txt") Resource wordDenyResource,
                     @Value("classpath:word/allow.txt") Resource wordAllowResource) {
        this.chatClient = chatClient;
        this.systemPromptResource = systemPromptResource;
        this.knowledgeResource = knowledgeResource;
        this.wordDenyResource = wordDenyResource;
        this.wordAllowResource = wordAllowResource;
        loadPromptFiles();
        loadSensitiveWord();
    }

    @Scheduled(fixedDelay = 10_000)
    public void reloadIfNeeded() {
        loadPromptFiles();
        loadSensitiveWord();
    }

    private void loadPromptFiles() {
        try {
            String newSystem = readResource(systemPromptResource);
            String newKnowledge = readResource(knowledgeResource);
            if (!newSystem.equals(systemPrompt) || !newKnowledge.equals(knowledgeBase)) {
                this.systemPrompt = newSystem;
                this.knowledgeBase = newKnowledge;
                log.info("Prompt 文件已热更新");
            }
        } catch (Exception e) {
            log.error("加载 Prompt 文件失败", e);
        }
    }

    /** 自定义违禁词*/
    public class MyWordDeny implements IWordDeny {
        @Override
        public List<String> deny() {
            List<String> denyWords;
            try {
                denyWords = readLines(wordDenyResource);
                return denyWords;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /** 自定义白名单词*/
    public class MyWordAllow implements IWordAllow {
        @Override
        public List<String> allow() {
            List<String> allowWords;
            try {
                allowWords = readLines(wordAllowResource);
                return allowWords;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

    /** 热更新写法*/
    private void loadSensitiveWord() {
        try {
            IWordDeny wordDeny = new MyWordDeny();
            IWordAllow wordAllow = new MyWordAllow();
            //使用官方自定义敏感词库
            SensitiveWordBs newBs = SensitiveWordBs.newInstance()
                    .wordDeny(wordDeny)
                    .wordAllow(wordAllow)
                    .ignoreCase(true)
                    .ignoreWidth(true)
                    .enableNumCheck(false)
                    .enableEmailCheck(false)
                    .enableUrlCheck(false)
                    .init();  // 必须 init()

            this.sensitiveWordBs = newBs;
            log.info("违禁词库热更新成功");

        } catch (Exception e) {
            log.error("加载违禁词库失败，使用旧实例", e);
            e.printStackTrace();
        }
    }

    private String readResource(Resource resource) throws IOException {
        if (resource == null) {
            return "";
        }
        return resource.getContentAsString(StandardCharsets.UTF_8).trim();
    }

    private List<String> readLines(Resource resource) throws IOException {

        String content = readResource(resource);
        return content.lines()
                .map(String::trim)
                .filter(s -> !s.isEmpty() && !s.startsWith("#"))
                .toList();
    }

    public Flux<String> ask(String question) {
        if (sensitiveWordBs == null) {
            return Flux.error(new RuntimeException("违禁词库未初始化"));
        }

        if (sensitiveWordBs.contains(question)) {
            List<String> badWords = sensitiveWordBs.findAll(question);
            log.warn("用户提问含违禁词：{}", badWords);
            return Flux.just("抱歉，您的提问包含敏感内容，请文明交流~");
        }

        try {
            String systemPrompt = StreamUtils.copyToString(systemPromptResource.getInputStream(), StandardCharsets.UTF_8);
            String knowledge = StreamUtils.copyToString(knowledgeResource.getInputStream(), StandardCharsets.UTF_8);

            String userTemplate = """
                    {knowledge}
                    用户问题：{question}
                    请根据上面的知识内容，使用友好、专业的语气回答用户问题。
                    """;
            PromptTemplate userPromptTemplate = new PromptTemplate(userTemplate);
            Message userMessage = userPromptTemplate.createMessage(
                    Map.of("knowledge", knowledge, "question", question));

            SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
            Message systemMessage = systemPromptTemplate.createMessage();

            Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

            return chatClient.stream(prompt)
                    .map(chatResponse -> {
                        AssistantMessage aiMessage = chatResponse.getResult().getOutput();
                        String content = aiMessage != null ? aiMessage.getContent() : "";
                        if (content.isBlank()) return "";

//                        if (sensitiveWordBs.contains(content)) {
//                            List<String> badWords = sensitiveWordBs.findAll(content);
//                            log.warn("AI 输出含违禁词：{}，已自动过滤", badWords);
//                            content = sensitiveWordBs.replace(content);
//                        }
                        return content;
                    })
                    .doOnError(e -> log.error("AI 调用异常", e));

        } catch (IOException e) {
            log.error("读取 prompt 文件失败", e);
            return Flux.error(new RuntimeException("加载提示词失败", e));
        }
    }
}